/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       water.vert
 * Author:     karooolek
 * Created on: Dec 18, 2009
 *
 **********************************************************************************************************************/

STRINGIZE(

varying vec4 position;
varying mat3 tbn;
varying mat3 modelMatrix;

uniform float t;

uniform vec4 a;
uniform vec4 l;
uniform vec4 q;
uniform mat4 vel;

uniform float normalMapScale;
uniform vec2 normalMapSize;

uniform vec2 foamSize;

void main()
{
    vec4 p1;
    vec4 p2;
    vec4 dir;

    // projected grid
    p1 = gl_ModelViewProjectionMatrixInverse * vec4(gl_Vertex.xy, -1.0, 1.0);
    p1 /= p1.w;
    p2 = gl_ModelViewProjectionMatrixInverse * vec4(gl_Vertex.xy, 1.0, 1.0);
    p2 /= p2.w;
    p2.z = min(p1.z - 0.01, p2.z);
    
    dir = normalize(p2 - p1);
    position = vec4(p1.xyz - p1.z / dir.z * dir.xyz, 1.0);
    
    // LOD
    p1 = gl_ModelViewProjectionMatrixInverse * vec4(gl_Vertex.xy + vec2(0.0, 0.01), -1.0, 1.0);
    p1 /= p1.w;
    p2 = gl_ModelViewProjectionMatrixInverse * vec4(gl_Vertex.xy + vec2(0.0, 0.01), 1.0, 1.0);
    p2 /= p2.w;
    p2.z = min(p1.z - 0.01, p2.z);
    
    dir = normalize(p2 - p1);
    p2 = vec4(p1.xyz - p1.z / dir.z * dir.xyz, 1.0);
    
    float lod = min(0.5 / length(p2 - position), 1.0);
    
    // initial tangent and normal
    vec3 tangent;
    vec3 normal;
    
    // sum four gerstner waves
    for(int i = 0; i != 4; ++i)
    {
        // direction and velocity
        vec2 dir = -vec2(vel[i]);
        float v = length(dir);
        dir = normalize(dir);
        
        float w = 6.28318531 / l[i];
        float wa = w * a[i];
        float qw = q[i] / w;
        float qwa = q[i] / wa;
        float d = dot(dir, vec2(position));
        float x = w * (t * v + d);
        float cosx = cos(x);
        float cosxx = cosx * dir.x;
        float cosxy = cosx * dir.y;
        float sinx = sin(x);
        float sinxx = sinx * dir.x;
    
        // wave position
        position.x += qw * cosxx;
        position.y += qw * cosxy;
        position.z += a[i] * sinx;
        
        // wave tangent
        tangent.x -= q[i] * sinxx * dir.x;
        tangent.y -= q[i] * sinxx * dir.y;
        tangent.z += w * a[i] * cosxx;
        
        // wave normal
        normal.x -= wa * cosxx;
        normal.y -= wa * cosxy;
        normal.z -= 0.25 * q[i] * sinx;
    }
    
    tangent = lod * tangent + vec3(1.0, 0.0, 0.0);
    normal = lod * normal + vec3(0.0, 0.0, 1.0);
    
    // pass normal map coordinates
    vec4 wvel = 0.0025 * (vel[0] + vel[1] + vel[2] + vel[3] + vec4(1.0, 1.0, 0.0, 0.0));
    gl_TexCoord[0] = vec4(normalMapSize, 1.0, 1.0) * position - wvel * t;
    gl_TexCoord[1] = vec4(normalMapSize, 1.0, 1.0) * position + wvel * t;

    // pass foam texture coordinates
    gl_TexCoord[2] = vec4(foamSize, 1.0, 1.0) * position;

    // transform vertex
    gl_Position = gl_ModelViewProjectionMatrix * position;
    position = gl_ModelViewMatrix * position;
    
    // pass model matrix
    modelMatrix[0][0] = gl_ModelViewMatrix[0][0];
    modelMatrix[0][1] = gl_ModelViewMatrix[1][0];
    modelMatrix[0][2] = gl_ModelViewMatrix[2][0];
    
    modelMatrix[1][0] = gl_ModelViewMatrix[0][1];
    modelMatrix[1][1] = gl_ModelViewMatrix[1][1];
    modelMatrix[1][2] = gl_ModelViewMatrix[2][1];
    
    modelMatrix[2][0] = gl_ModelViewMatrix[0][2];
    modelMatrix[2][1] = gl_ModelViewMatrix[1][2];
    modelMatrix[2][2] = gl_ModelViewMatrix[2][2];
    
    // pass tangent, binormal, normal matrix
    tangent = normalMapScale * normalize(tangent);
    normal = normalize(normal);
    tbn = gl_NormalMatrix * mat3(tangent, cross(normal, tangent), normal);
}

) // STRINGIZE
